import { ECSErr } from "../err/ECSErr";
import { ArrUtil } from "../util/ArrUtil";
import { Cls } from "../util/Defined";
import { TypeUtil } from "../util/TypeUtil";
import { ECSMgr } from "./ECSMgr";
import { ECSSceneState } from "./ECSScene";
import { ECSSys } from "./ECSSys";

/**
 * [ECS]系统管理
 */
export class ECSSysMgr extends ECSMgr {
	/** 所有系统 */
	protected _sysMap = new Map<Cls<ECSSys>, ECSSys>();
	/** 系统队列 */
	protected _systems: ECSSys[] = [];

	/** 暂停中 */
	paused: boolean = false;

	/**
	 * 添加系统
	 * @param sysType 系统类型
	 */
	add<T extends ECSSys>(sysType: Cls<T>) {
		if (this.scene.state !== ECSSceneState.init) {
			throw new ECSErr("请在初始化阶段 添加系统");
		}

		if (this._sysMap.has(sysType)) {
			throw new ECSErr("重复添加系统");
		}
		const sys = new sysType(this.scene);
		this._sysMap.set(sysType, sys);
		this._systems.push(sys);
		sys.filter = this.scene.filterMgr.genFilter(sys.ifilter);
		return sys as T;
	}

	/**
	 * 移除系统
	 * @param sysType 系统类型
	 */
	remove<T extends ECSSys>(sysType: Cls<T>) {
		const sys = this._sysMap.get(sysType);
		if (sys) {
			this._sysMap.delete(sysType);
			ArrUtil.remove(this._systems, sys);
			return true;
		}
		return false;
	}

	/**
	 * 场景启动时触发
	 */
	onStart() {
		//根据系统更新顺序进行排序
		this._systems.sort((a, b) => a.updateOrder - b.updateOrder);
		this._systems.forEach(sys => sys.doStart());
	}

	/**
	 * 帧循环更新系统
	 */
	update() {
		if (this.paused) return;
		this._systems.forEach(this.updateSys, this);
	}

	private updateSys(sys: ECSSys) {
		sys.doUpdate();
	}

	protected onDestroy() {
		this._systems.forEach(sys => sys.onDestroy?.());
		this._systems.length = 0;
		this._sysMap.clear();
	}

	// ============ DEBUG ============

	/**
	 * 开启所有系统的调试运行时间记录
	 */
	enableDebugRecordAll() {
		this._sysMap.forEach(sys => sys.enableDebugRecord());
	}

	/**
	 * 调试报告
	 */
	getDebugReport() {
		const records: {
			sys: ECSSys;
			records: Map<
				string,
				{
					count: number;
					least: number;
					total: number;
					avg: number;
				}
			>;
		}[] = [];
		this._sysMap.forEach(sys => sys.debugRecord && records.push({ sys, records: sys.debugRecord }));
		return records.sort((a, b) => b.records.get("total").total - a.records.get("total").total);
	}

	/**
	 * 打印调试报告
	 */
	printDebugReport() {
		const report = this.getDebugReport();
		let str = "";
		str += `\x1B[31m============ 系统调试报告 ============\x1B[0m\n`;
		str += `\n`;
		str += `已运行时间：${this.scene.runTime}s\n`;
		str += `已运行帧数：${this.scene.runFrame}\n`;
		str += `\n`;
		report.forEach(sys => {
			str += `\x1B[36m${TypeUtil.getCls(sys.sys).name}\x1B[0m\n`;
			sys.records.forEach((record, key) => {
				str += `\x1B[33m${key}\x1B[0m ${Array.from({ length: 14 - key.length }, () => " ").join("")} 单次：\x1B[32m${record.least.toFixed(6)}ms\x1B[0m 平均：\x1B[32m${record.avg.toFixed(
					6
				)}ms\x1B[0m\n`;
			});
		});
		str += `\n`;
		str += `\x1B[31m============ 系统调试报告 ============\x1B[0m\n`;
		this.scene.logger.log(str);
	}
}
